package com.czk.bootlettuce.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.*;

import java.util.List;

/**
 * redis秒杀
 *
 * @Author:ChenZhangKun
 * @Date: 2021/8/17 16:59
 */
@Configuration
public class SeckillUtil {
    @Autowired
    private StringRedisTemplate redisTemplate;

    public boolean soSecKill(String uid, String prodid) {

        // 非空判断
        if (uid == null || prodid == null) {
            return false;
        }
        // 凭借key
        // 库存key
        String kcKey = "sk:" + prodid + ":qt";
        // 用户key
        String userKey = "sk:" + prodid + ":user";
        // 监视库存
        // 在执行multi之前，先执行watch key1 [key2],可以监视一个(或多个) key ，
        // 如果在事务执行之前这个(或这些) key 被其他命令所改动，那么事务将被打断 基于乐观锁的机制
        redisTemplate.watch(kcKey);
        // 库存
        Object kc = redisTemplate.opsForValue().get(kcKey);
        if (kc == null) {
            System.out.println("秒杀尚未开始");
            return false;
        }
        // 判断用户是否重复秒杀
        Boolean b = redisTemplate.opsForSet().isMember(userKey, uid);
        if (b) {
            System.out.println("用户已经秒杀成功，不能重复参与");
            return false;
        }
        // 判断库存
        if (Integer.parseInt(kc + "") <= 0) {
            System.out.println("秒杀结束");
            return false;
        }
        ValueOperations valueOperations = redisTemplate.opsForValue();
        SetOperations setOperations = redisTemplate.opsForSet();
        // 开启事务支持
        redisTemplate.setEnableTransactionSupport(true);
        List<Object> result = redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations redisOperations) throws DataAccessException {
                // 使用事务->z组队阶段
                redisTemplate.multi();
                // 组队操作
                // 秒杀库存减一
                valueOperations.decrement(kcKey);
                // 用户加入set集合
                setOperations.add(userKey, uid);
                // 执行->执行阶段
                return redisTemplate.exec();
            }
        });


        if (result.size() == 0) {
            System.out.println("秒杀失败了");
            return false;
        }
        return true;
    }
}
